#ifndef SERVICE_URL_PARSER_H
#define SERVICE_URL_PARSER_H

#include <boost/spirit/core.hpp>
#include <boost/spirit/phoenix/primitives.hpp>
#include <boost/spirit/phoenix/operators.hpp>
#include <boost/spirit/attribute.hpp>
#include <boost/spirit/actor.hpp>
#include <boost/spirit/utility/confix.hpp>
#include <boost/spirit/dynamic.hpp>
#include <boost/logic/tribool.hpp>
#include <iostream>
#include <string>
#include <map>

namespace vpm
{
	namespace mina
	{		
		using namespace boost::spirit;
		using namespace phoenix;

		//; the scheme is in lower case; interpreters should use case-ignore
		//scheme         = 1*[ lowalpha | digit | "+" | "-" | "." ]
		static rule<phrase_scanner_t> scheme_p  = +(alnum_p | ch_p('+') | ch_p('-') | ch_p('.')) ; 

		//domainlabel    = alphadigit | alphadigit *[ alphadigit | "-" ] alphadigit
		static rule<phrase_scanner_t> domainlabel_p = alnum_p | (alnum_p >> *(alnum_p | ch_p('-')) >>alnum_p ); 

		//toplabel       = alpha | alpha *[ alphadigit | "-" ] alphadigit
		static rule<phrase_scanner_t> toplabel_p = alpha_p | (alpha_p >> *(alnum_p | '-') >> alnum_p);

		//hostname       = *[ domainlabel "." ] toplabel
		static rule<phrase_scanner_t> hostname_p =  *(domainlabel_p >> '.') >> toplabel_p; 

		//hostnumber     = digits "." digits "." digits "." digits
		static rule<phrase_scanner_t> hostnumber_p = +digit_p >> '.'>>+digit_p  >> '.' >> +digit_p >>'.'>> +digit_p;

		static rule<phrase_scanner_t> host_p = hostname_p | hostnumber_p; 

		static rule<phrase_scanner_t> port_p = +digit_p ; 

		//static rule<phrase_scanner_t> hostport_p = host_p >> !(':'>>port_p);


		//compare two string base on the shorter string's length, don't compare the end '\0'
		struct short_string_cmp
		{
			bool operator()(const char * shorter, const char * other)
			{
				if (*shorter == '\0')
				{
					return true; 
				}
				const char * p = shorter; 
				while (*p != 0)
				{
					if (*p != to_lower(*(other + (p - shorter))))
					{
						return false; 
					}
					p++;
				}

				return true; 
			}

			char to_lower(char ch)
			{
				if (ch >= 'A' && ch <= 'Z')
				{
					return (ch - ('A'-'a'));
				}
				return ch; 
			}
		};

		struct scheme_a
		{
			scheme_a(ServiceUrl & url):serviceUrl(url)
			{
			}
			void operator() ( const char * beg, const char * end) const
			{
				short_string_cmp cmper;
				if (cmper("tcp",beg))
				{
					serviceUrl.schemeType = ServiceUrl::TCP;
					serviceUrl.scheme = "tcp";
				}
				else if (cmper("udp",beg))
				{
					serviceUrl.schemeType = ServiceUrl::UDP;
					serviceUrl.scheme = "udp";
				}		
			}

			ServiceUrl& serviceUrl;
		};



		class ServiceUrlParser :public grammar<ServiceUrlParser>
		{
		public:
			ServiceUrlParser (ServiceUrl & url):serviceUrl(url)
			{

			}
			template <typename ScannerT>
			struct definition
			{
				definition(ServiceUrlParser const & self)
				{
					r_expression  =  scheme_p[scheme_a(self.serviceUrl)] >> str_p("://") >> r_scheme_specific_part; 
					r_scheme_specific_part =  host_p[assign(self.serviceUrl.host)] >> !(':'>>int_p[assign_a(self.serviceUrl.port)]) >> *anychar_p;
				}

				rule<ScannerT> const & start()
				{
					return r_expression;
				}

				rule<ScannerT> r_expression;
				rule<ScannerT> r_scheme_specific_part;	
			};

		private:
			ServiceUrl & serviceUrl; 
		};

	}
}
#endif // 

